<template>
  <div class="captcha-container">
    <!-- 图片验证码 -->
    <div v-if="captchaType === 'image' || captchaType === 'math'" class="image-captcha">
      <div class="captcha-input-group">
        <el-input
          v-model="userInput"
          placeholder="请输入验证码"
          :disabled="loading"
          @keyup.enter="handleVerify"
          clearable
        >
          <template #append>
            <div class="captcha-image-wrapper" @click="refreshCaptcha">
              <img 
                v-if="captchaData.imageBase64" 
                :src="captchaData.imageBase64" 
                :alt="captchaType === 'math' ? '数学运算验证码' : '图片验证码'"
                class="captcha-image"
              />
              <div v-else class="captcha-placeholder">
                <el-icon><Refresh /></el-icon>
                <span>点击获取</span>
              </div>
            </div>
          </template>
        </el-input>
      </div>
      <div class="captcha-tips">
        <span>{{ captchaType === 'math' ? '请计算结果' : '点击图片刷新验证码' }}</span>
        <el-button 
          type="text" 
          size="small" 
          @click="refreshCaptcha"
          :loading="loading"
        >
          <el-icon><Refresh /></el-icon>
          刷新
        </el-button>
      </div>
    </div>

    <!-- 滑块验证码 -->
    <div v-else-if="captchaType === 'slider'" class="slider-captcha">
      <div class="slider-container" ref="sliderContainer">
        <div class="slider-background">
          <img
            v-if="captchaData.backgroundImage"
            :src="captchaData.backgroundImage"
            alt="滑块验证码背景"
            class="background-image"
            @dragstart.prevent
          />
        </div>

        <div
          class="slider-piece"
          :class="{ 'dragging': isDragging, 'success': verifySuccess }"
          :style="{
            left: sliderPosition + 'px',
            top: (captchaData.y || 0) + 'px',
            transform: isDragging ? 'scale(1.05)' : 'scale(1)'
          }"
          v-if="captchaData.sliderImage"
        >
          <img
            :src="captchaData.sliderImage"
            alt="滑块"
            class="slider-image"
            @dragstart.prevent
          />
        </div>
      </div>

      <div class="slider-track">
        <div
          class="slider-track-bg"
          :class="{
            'success': verifySuccess,
            'error': verifyError,
            'active': isDragging
          }"
        >
          <div class="slider-progress" :style="{ width: sliderProgress + '%' }"></div>
          <span class="slider-text" :class="{ 'success': verifySuccess, 'error': verifyError }">
            {{ sliderText }}
          </span>
        </div>
        <div
          class="slider-button"
          :class="{
            'dragging': isDragging,
            'success': verifySuccess,
            'error': verifyError
          }"
          :style="{ left: sliderPosition + 'px' }"
          @mousedown="startDrag"
          @touchstart="startDrag"
        >
          <el-icon v-if="!verifySuccess && !verifyError"><Right /></el-icon>
          <el-icon v-else-if="verifySuccess" class="success-icon"><Check /></el-icon>
          <el-icon v-else class="error-icon"><Close /></el-icon>
        </div>
      </div>

      <div class="captcha-tips">
        <span>{{ isDragging ? '继续拖动到正确位置' : '拖动滑块完成验证' }}</span>
        <el-button
          type="text"
          size="small"
          @click="refreshCaptcha"
          :loading="loading"
          :disabled="isDragging"
        >
          <el-icon><Refresh /></el-icon>
          刷新
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted, defineEmits, defineProps } from 'vue'
import { ElMessage } from 'element-plus'
import { Refresh, Right, Check, Close } from '@element-plus/icons-vue'
import { generateCaptcha, verifyCaptcha, verifySliderCaptcha, refreshCaptcha as refreshCaptchaApi } from '../api/captcha'

const props = defineProps({
  type: {
    type: String,
    default: 'image' // image, math, slider
  },
  required: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['verify-success', 'verify-failed'])

const loading = ref(false)
const userInput = ref('')
const captchaType = ref(props.type)
const captchaData = reactive({
  captchaId: '',
  imageBase64: '',
  backgroundImage: '',
  sliderImage: '',
  y: 0
})

// 滑块相关
const sliderPosition = ref(0)
const sliderText = ref('向右滑动验证')
const sliderProgress = ref(0)
const isDragging = ref(false)
const verifySuccess = ref(false)
const verifyError = ref(false)
const startX = ref(0)
const sliderContainer = ref(null)

// 初始化验证码
const initCaptcha = async () => {
  if (!props.required) return
  
  try {
    loading.value = true
    const response = await generateCaptcha(captchaType.value)
    
    Object.assign(captchaData, response.data)
    userInput.value = ''
    resetSliderState()
    
  } catch (error) {
    console.error('初始化验证码失败:', error)
    ElMessage.error('获取验证码失败')
  } finally {
    loading.value = false
  }
}

// 刷新验证码
const refreshCaptcha = async () => {
  if (!props.required) return
  
  try {
    loading.value = true
    const response = await refreshCaptchaApi(captchaType.value, captchaData.captchaId)
    
    Object.assign(captchaData, response.data)
    userInput.value = ''
    resetSliderState()
    
  } catch (error) {
    console.error('刷新验证码失败:', error)
    ElMessage.error('刷新验证码失败')
  } finally {
    loading.value = false
  }
}

// 验证验证码
const handleVerify = async () => {
  if (!props.required) {
    emit('verify-success')
    return
  }
  
  if (!captchaData.captchaId) {
    ElMessage.error('请先获取验证码')
    return
  }
  
  if (captchaType.value === 'slider') {
    return // 滑块验证码在拖拽结束时自动验证
  }
  
  if (!userInput.value.trim()) {
    ElMessage.error('请输入验证码')
    return
  }
  
  try {
    loading.value = true
    await verifyCaptcha(captchaData.captchaId, userInput.value.trim())
    
    ElMessage.success('验证码验证成功')
    emit('verify-success', {
      captchaId: captchaData.captchaId,
      userInput: userInput.value.trim()
    })
    
  } catch (error) {
    console.error('验证码验证失败:', error)
    ElMessage.error(error.response?.data?.message || '验证码错误')
    emit('verify-failed')
    
    // 验证失败后刷新验证码
    setTimeout(() => {
      refreshCaptcha()
    }, 1000)
  } finally {
    loading.value = false
  }
}

// 重置滑块状态
const resetSliderState = () => {
  sliderPosition.value = 0
  sliderProgress.value = 0
  sliderText.value = '向右滑动验证'
  verifySuccess.value = false
  verifyError.value = false
  isDragging.value = false
}

// 滑块拖拽开始
const startDrag = (e) => {
  if (!props.required || verifySuccess.value || loading.value) return

  // 重置错误状态
  verifyError.value = false

  isDragging.value = true
  startX.value = e.type === 'mousedown' ? e.clientX : e.touches[0].clientX
  sliderText.value = '继续拖动...'

  document.addEventListener('mousemove', onDrag, { passive: false })
  document.addEventListener('mouseup', endDrag)
  document.addEventListener('touchmove', onDrag, { passive: false })
  document.addEventListener('touchend', endDrag)

  e.preventDefault()
}

// 滑块拖拽中
const onDrag = (e) => {
  if (!isDragging.value) return

  const currentX = e.type === 'mousemove' ? e.clientX : e.touches[0].clientX
  const deltaX = currentX - startX.value
  const maxPosition = 270 // 滑块轨道宽度 - 滑块宽度 (320 - 50)

  const newPosition = Math.max(0, Math.min(maxPosition, deltaX))
  sliderPosition.value = newPosition
  sliderProgress.value = (newPosition / maxPosition) * 100

  // 更新提示文本
  if (sliderProgress.value > 80) {
    sliderText.value = '即将完成验证'
  } else if (sliderProgress.value > 50) {
    sliderText.value = '继续拖动...'
  } else {
    sliderText.value = '向右拖动滑块'
  }

  e.preventDefault()
}

// 滑块拖拽结束
const endDrag = async () => {
  if (!isDragging.value) return

  isDragging.value = false

  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', endDrag)
  document.removeEventListener('touchmove', onDrag)
  document.removeEventListener('touchend', endDrag)

  // 验证滑块位置
  try {
    loading.value = true
    sliderText.value = '验证中...'

    await verifySliderCaptcha(captchaData.captchaId, sliderPosition.value)

    // 验证成功
    verifySuccess.value = true
    sliderText.value = '验证成功'
    sliderProgress.value = 100

    ElMessage.success('验证成功')
    emit('verify-success', {
      captchaId: captchaData.captchaId,
      x: sliderPosition.value
    })

  } catch (error) {
    console.error('滑块验证失败:', error)

    // 验证失败
    verifyError.value = true
    sliderText.value = '验证失败，请重试'

    ElMessage.error('验证失败，请重试')
    emit('verify-failed')

    // 验证失败后延迟重置
    setTimeout(() => {
      resetSliderState()
      refreshCaptcha()
    }, 1500)
  } finally {
    loading.value = false
  }
}

// 暴露验证方法给父组件
const verify = () => {
  return handleVerify()
}

// 暴露刷新方法给父组件
const refresh = () => {
  return refreshCaptcha()
}

// 获取验证码ID
const getCaptchaId = () => {
  return captchaData.captchaId
}

// 获取用户输入
const getUserInput = () => {
  return userInput.value
}

defineExpose({
  verify,
  refresh,
  getCaptchaId,
  getUserInput
})

onMounted(() => {
  initCaptcha()
})

onUnmounted(() => {
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', endDrag)
  document.removeEventListener('touchmove', onDrag)
  document.removeEventListener('touchend', endDrag)
})
</script>

<style scoped>
.captcha-container {
  width: 100%;
}

.image-captcha {
  width: 100%;
}

.captcha-input-group {
  margin-bottom: 8px;
}

.captcha-image-wrapper {
  width: 120px;
  height: 40px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f5f5;
  border-left: 1px solid #dcdfe6;
}

.captcha-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.captcha-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #909399;
  font-size: 12px;
}

.captcha-tips {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  color: #909399;
}

.slider-captcha {
  width: 100%;
}

.slider-container {
  position: relative;
  width: 320px;
  height: 160px;
  margin-bottom: 15px;
  border: 2px solid #e4e7ed;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  background: #f8f9fa;
}

.slider-background {
  width: 100%;
  height: 100%;
}

.background-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.slider-piece {
  position: absolute;
  width: 42px;
  height: 42px;
  z-index: 2;
  transition: transform 0.2s ease;
  filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.3));
}

.slider-piece.dragging {
  filter: drop-shadow(4px 4px 8px rgba(0, 0, 0, 0.4));
}

.slider-piece.success {
  filter: drop-shadow(0 0 10px rgba(67, 160, 71, 0.6));
}

.slider-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.slider-track {
  position: relative;
  width: 320px;
  height: 50px;
  background: #f5f7fa;
  border: 2px solid #e4e7ed;
  border-radius: 25px;
  margin-bottom: 10px;
  overflow: hidden;
}

.slider-track-bg {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 23px;
  position: relative;
  background: #f5f7fa;
  transition: all 0.3s ease;
}

.slider-track-bg.active {
  background: linear-gradient(to right, #e3f2fd, #f5f7fa);
}

.slider-track-bg.success {
  background: linear-gradient(to right, #c8e6c9, #4caf50);
}

.slider-track-bg.error {
  background: linear-gradient(to right, #ffcdd2, #f44336);
}

.slider-progress {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  background: linear-gradient(to right, #42a5f5, #1e88e5);
  border-radius: 23px;
  transition: width 0.1s ease;
  opacity: 0.3;
}

.slider-text {
  color: #606266;
  font-size: 14px;
  font-weight: 500;
  user-select: none;
  z-index: 2;
  position: relative;
  transition: color 0.3s ease;
}

.slider-text.success {
  color: #ffffff;
  font-weight: 600;
}

.slider-text.error {
  color: #ffffff;
  font-weight: 600;
}

.slider-button {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 44px;
  height: 44px;
  background: linear-gradient(135deg, #ffffff, #f5f5f5);
  border: 2px solid #e4e7ed;
  border-radius: 22px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
  z-index: 3;
}

.slider-button:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
}

.slider-button.dragging {
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
  transform: scale(1.1);
  background: linear-gradient(135deg, #e3f2fd, #bbdefb);
  border-color: #2196f3;
}

.slider-button.success {
  background: linear-gradient(135deg, #c8e6c9, #4caf50);
  border-color: #4caf50;
  box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
}

.slider-button.error {
  background: linear-gradient(135deg, #ffcdd2, #f44336);
  border-color: #f44336;
  box-shadow: 0 4px 12px rgba(244, 67, 54, 0.3);
}

.success-icon {
  color: #ffffff;
  font-weight: bold;
}

.error-icon {
  color: #ffffff;
  font-weight: bold;
}
</style>
